Trò chơi Tic-Tac-Toe, game đánh caro full source code
- PhotonViewHandler.cs
- PhotonNetwork /
- Editor /
- Photon Unity Networking /
- Assets /
- project /
2 using System.Diagnostics;
3 using System.IO;
4 using UnityEditor;
5 using UnityEngine;
6 using System.Collections;
7 using Debug = UnityEngine.Debug;
8
9 [InitializeOnLoad]
10 public class PhotonViewHandler : EditorWindow
11 {
12 private static bool CheckSceneForStuckHandlers = true;
13
14 static PhotonViewHandler()
15 {
16 // hierarchyWindowChanged is called on hierarchy changed and on save. It's even called when hierarchy-window is closed and if a prefab with instances is changed.
17 // this is not called when you edit a instance's value but: on save
18 EditorApplication.hierarchyWindowChanged += HierarchyChange;
19 }
20
21 // this method corrects the IDs for photonviews in the scene and in prefabs
22 // make sure prefabs always use viewID 0
23 // make sure instances never use a owner
24 // this is a editor class that should only run if not playing
25 internal static void HierarchyChange()
26 {
27 if (Application.isPlaying)
28 {
29 //Debug.Log("HierarchyChange ignored, while running.");
30 CheckSceneForStuckHandlers = true; // done once AFTER play mode.
31 return;
32 }
33
34 if (CheckSceneForStuckHandlers)
35 {
36 CheckSceneForStuckHandlers = false;
37 PhotonNetwork.InternalCleanPhotonMonoFromSceneIfStuck();
38 }
39
40 HashSet<PhotonView> pvInstances = new HashSet<PhotonView>();
41 HashSet<int> usedInstanceViewNumbers = new HashSet<int>();
42 bool fixedSomeId = false;
43
44 //// the following code would be an option if we only checked scene objects (but we can check all PVs)
45 //PhotonView[] pvObjects = GameObject.FindSceneObjectsOfType(typeof(PhotonView)) as PhotonView[];
46 //Debug.Log("HierarchyChange. PV Count: " + pvObjects.Length);
47
48 string levelName = Application.loadedLevelName;
49 #if UNITY_EDITOR
50 levelName = System.IO.Path.GetFileNameWithoutExtension(EditorApplication.currentScene);
51 #endif
52 int minViewIdInThisScene = PunSceneSettings.MinViewIdForScene(levelName);
53 //Debug.Log("Level '" + Application.loadedLevelName + "' has a minimum ViewId of: " + minViewIdInThisScene);
54
55 PhotonView[] pvObjects = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[];
56
57 foreach (PhotonView view in pvObjects)
58 {
59 // first pass: fix prefabs to viewID 0 if they got a view number assigned (cause they should not have one!)
60 if (EditorUtility.IsPersistent(view.gameObject))
61 {
62 if (view.viewID != 0 || view.prefixBackup != -1 || view.instantiationId != -1)
63 {
64 Debug.LogWarning("PhotonView on persistent object being fixed (id and prefix must be 0). Was: " + view);
65 view.viewID = 0;
66 view.prefixBackup = -1;
67 view.instantiationId = -1;
68 EditorUtility.SetDirty(view);
69 fixedSomeId = true;
70 }
71 }
72 else
73 {
74 // keep all scene-instanced PVs for later re-check
75 pvInstances.Add(view);
76 }
77 }
78
79 Dictionary<GameObject, int> idPerObject = new Dictionary<GameObject, int>();
80
81 // second pass: check all used-in-scene viewIDs for duplicate viewIDs (only checking anything non-prefab)
82 // scene-PVs must have user == 0 (scene/room) and a subId != 0
83 foreach (PhotonView view in pvInstances)
84 {
85 if (view.ownerId > 0)
86 {
87 Debug.Log("Re-Setting Owner ID of: " + view);
88 }
89 view.ownerId = 0; // simply make sure no owner is set (cause room always uses 0)
90 view.prefix = -1; // TODO: prefix could be settable via inspector per scene?!
91
92 if (view.viewID != 0)
93 {
94 if (view.viewID < minViewIdInThisScene || usedInstanceViewNumbers.Contains(view.viewID))
95 {
96 view.viewID = 0; // avoid duplicates and negative values by assigning 0 as (temporary) number to be fixed in next pass
97 }
98 else
99 {
100 usedInstanceViewNumbers.Add(view.viewID); // builds a list of currently used viewIDs
101
102 int instId = 0;
103 if (idPerObject.TryGetValue(view.gameObject, out instId))
104 {
105 view.instantiationId = instId;
106 }
107 else
108 {
109 view.instantiationId = view.viewID;
110 idPerObject[view.gameObject] = view.instantiationId;
111 }
112 }
113 }
114
115 }
116
117 // third pass: anything that's now 0 must get a new (not yet used) ID (starting at 0)
118 int lastUsedId = (minViewIdInThisScene > 0) ? minViewIdInThisScene - 1 : 0;
119
120 foreach (PhotonView view in pvInstances)
121 {
122 if (view.viewID == 0)
123 {
124 // Debug.LogWarning("setting scene ID: " + view.gameObject.name + " ID: " + view.subId.ID + " scene ID: " + view.GetSceneID() + " IsPersistent: " + EditorUtility.IsPersistent(view.gameObject) + " IsSceneViewIDFree: " + IsSceneViewIDFree(view.subId.ID, view));
125 int nextViewId = PhotonViewHandler.GetID(lastUsedId, usedInstanceViewNumbers);
126
127 view.viewID = nextViewId;
128
129 int instId = 0;
130 if (idPerObject.TryGetValue(view.gameObject, out instId))
131 {
132 Debug.Log("Set inst ID");
133 view.instantiationId = instId;
134 }
135 else
136 {
137 view.instantiationId = view.viewID;
138 idPerObject[view.gameObject] = nextViewId;
139 }
140
141 //// when using the Editor's serialization (view.subId in this case), this is not needed, it seems
142 //PrefabUtility.RecordPrefabInstancePropertyModifications(view);
143
144 lastUsedId = nextViewId;
145 EditorUtility.SetDirty(view);
146 fixedSomeId = true;
147 }
148 }
149
150
151 if (fixedSomeId)
152 {
153 //Debug.LogWarning("Some subId was adjusted."); // this log is only interesting for Exit Games
154 }
155 }
156
157 // TODO fail if no ID was available anymore
158 // TODO look up lower numbers if offset hits max?!
159 public static int GetID(int idOffset, HashSet<int> usedInstanceViewNumbers)
160 {
161 while (idOffset < PhotonNetwork.MAX_VIEW_IDS)
162 {
163 idOffset++;
164 if (!usedInstanceViewNumbers.Contains(idOffset))
165 {
166 break;
167 }
168 }
169
170 return idOffset;
171 }
172
173 //TODO: check if this can be internal protected (as source in editor AND as dll)
174 public static void LoadAllScenesToFix()
175 {
176 string[] scenes = System.IO.Directory.GetFiles(".", "*.unity", SearchOption.AllDirectories);
177
178 foreach (string scene in scenes)
179 {
180 EditorApplication.OpenScene(scene);
181
182 PhotonViewHandler.HierarchyChange();//TODO: most likely on load also triggers a hierarchy change
183
184 EditorApplication.SaveScene();
185 }
186
187 Debug.Log("Corrected scene views where needed.");
188 }
189 }
hierarchyWindowChanged is called on hierarchy changed and on save. It's even called when hierarchy-window is closed and if a prefab with instances is changed.
this is not called when you edit a instance's value but: on save
this method corrects the IDs for photonviews in the scene and in prefabs
make sure prefabs always use viewID 0
make sure instances never use a owner
this is a editor class that should only run if not playing
Debug.Log("HierarchyChange ignored, while running.");
CheckSceneForStuckHandlers = true; done once AFTER play mode.
the following code would be an option if we only checked scene objects (but we can check all PVs)
PhotonView[] pvObjects = GameObject.FindSceneObjectsOfType(typeof(PhotonView)) as PhotonView[];
Debug.Log("HierarchyChange. PV Count: " + pvObjects.Length);
Debug.Log("Level '" + Application.loadedLevelName + "' has a minimum ViewId of: " + minViewIdInThisScene);
first pass: fix prefabs to viewID 0 if they got a view number assigned (cause they should not have one!)
keep all scene-instanced PVs for later re-check
second pass: check all used-in-scene viewIDs for duplicate viewIDs (only checking anything non-prefab)
scene-PVs must have user == 0 (sceneroom) and a subId != 0
view.ownerId = 0; simply make sure no owner is set (cause room always uses 0)
view.prefix = -1; TODO: prefix could be settable via inspector per scene?!
view.viewID = 0; avoid duplicates and negative values by assigning 0 as (temporary) number to be fixed in next pass
usedInstanceViewNumbers.Add(view.viewID); builds a list of currently used viewIDs
third pass: anything that's now 0 must get a new (not yet used) ID (starting at 0)
Debug.LogWarning("setting scene ID: " + view.gameObject.name + " ID: " + view.subId.ID + " scene ID: " + view.GetSceneID() + " IsPersistent: " + EditorUtility.IsPersistent(view.gameObject) + " IsSceneViewIDFree: " + IsSceneViewIDFree(view.subId.ID, view));
when using the Editor's serialization (view.subId in this case), this is not needed, it seems
PrefabUtility.RecordPrefabInstancePropertyModifications(view);
Debug.LogWarning("Some subId was adjusted."); this log is only interesting for Exit Games
TODO fail if no ID was available anymore
TODO look up lower numbers if offset hits max?!
TODO: check if this can be internal protected (as source in editor AND as dll)
PhotonViewHandler.HierarchyChange();TODO: most likely on load also triggers a hierarchy change